package com.example.thread.base.demo4;

import lombok.extern.slf4j.Slf4j;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author LiYuhang
 * @version 0.1
 * @application 利用 Condition 实现生产者消费者模式
 * @Date 2020/12/16 10:00
 */
@Slf4j
public class demo4_3 {
    public static void main(String[] args) {
        MyBlockingQueueForCondition queue=new MyBlockingQueueForCondition(16);
        Runnable producer=()->{
            while (true){
                try {
                    queue.put(new Object());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };
        new Thread(producer).start();
        Runnable consumer=()->{
           while (true){
               try {
                  log.info("consumer{}",queue.take());
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
           }
        };
        new Thread(consumer,"thread1").start();
        new Thread(consumer,"thread2").start();
        new Thread(consumer,"thread3").start();
        new Thread(consumer,"thread4").start();
    }
}

class MyBlockingQueueForCondition {
    private Queue queue;
    private int max = 16;
    private ReentrantLock lock = new ReentrantLock();
    private Condition notEmpty = lock.newCondition();
    private Condition notFull = lock.newCondition();
    public MyBlockingQueueForCondition(int size) {
        this.max = size;
        queue = new LinkedList();
    }
    public  void put(Object o) throws InterruptedException {
        lock.lock();
        try {
            while (queue.size() == max) {
                notFull.await();
            }
            queue.add(o);
            notEmpty.signalAll();
        } finally {
            lock.unlock();
        }
    }
    public  Object take() throws InterruptedException {
        lock.lock();
        try {
            while (queue.size() == 0) {
                notEmpty.await();
            }
            Object item = queue.remove();
            notFull.signalAll();
            return item;
        } finally {
            lock.unlock();
        }
    }
}
